home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / 8250.c next >
C/C++ Source or Header  |  1994-07-11  |  10KB  |  487 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC */
  2. /* hacked to support BIOS interaction for NET PC9801 ala JK1NNT by N3EUA */
  3.  
  4. #include "config.h"
  5. #if !defined(PLUS)
  6.  
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "asy.h"
  10. #include "8250.h"
  11. #include "iface.h"
  12.  
  13. struct asy asy[ASY_MAX];
  14. unsigned nasy;
  15.  
  16. unsigned h2ivec[ASYHANDLE_MAX] ;
  17. unsigned nhandlers ;
  18.  
  19. struct ivec ivec[NIVECS] ;
  20.  
  21. #ifdef PC9801
  22. int work, f_handle, jkintdos();
  23. #define mask 0x00ff
  24. #endif
  25.  
  26. /* ASY interrupt handlers */
  27. #ifndef PC9801
  28. extern void asy0vec(),asy1vec(),asy2vec(),asy3vec(),asy4vec();
  29. void (*handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec};
  30. #endif
  31.  
  32. /* Initialize asynch port "dev" */
  33. int
  34. asy_init(dev,arg1,arg2,bufsize)
  35. int16 dev;
  36. char *arg1,*arg2;    /* Attach args for address and vector */
  37. unsigned bufsize;
  38. {
  39.     register unsigned base;
  40.     register struct fifo *fp;
  41.     register struct asy *ap;
  42.     unsigned vec ;
  43.     void (*getirq())();
  44.     char i_state;
  45.  
  46.     ap = &asy[dev];
  47.     ap->addr = htoi(arg1);
  48.     ap->vec = htoi(arg2);
  49.     /* Set up receiver FIFO */
  50.     fp = &ap->fifo;
  51.     if((fp->buf = malloc(bufsize)) == NULLCHAR){
  52.         printf("asy%d: No space for rx buffer\r\n",dev);
  53.         fflush(stdout);
  54.         return -1;
  55.     }
  56.     fp->bufsize = bufsize;
  57.     fp->wp = fp->rp = fp->buf;
  58.     fp->cnt = 0;
  59.  
  60.     base = ap->addr;
  61.     ap->urgent = NULLCHAR;    /* For SLFP urgent data */
  62.  
  63. #ifdef PC9801
  64.     f_handle = auxopen();
  65. #else
  66.     /* Purge the receive data buffer */
  67.     (void)inportb(base+RBR);
  68.  
  69.     i_state = disable();
  70.  
  71.     /* Set up interrupt vector structure if necessary */
  72.     vec = ap->vec ;
  73.     if (ivec[vec].ichain == NULLASY) {
  74.         if (nhandlers == ASYHANDLE_MAX) {
  75.             printf("asy%d: No more interrupt handlers\n",dev) ;
  76.             return ;
  77.         }
  78.  
  79.         /* Save original interrupt vector and mask */
  80.         ivec[vec].oldvec = getirq(ap->vec) ;
  81.         ivec[vec].oldmask = getmask(ap->vec) ;
  82.  
  83.         /* Set interrupt vector to SIO handler */
  84.         setirq(ap->vec,handle[nhandlers]);
  85.  
  86.         /* Set up correspondence between handler and interrupt */
  87.         h2ivec[nhandlers] = vec ;
  88.         
  89.         nhandlers++ ;        /* step to next handler */
  90.  
  91.         /* Start chain */
  92.         ivec[vec].ichain = &asy[dev] ;
  93.         ap->ichain = NULLASY ;        /* terminate the chain */
  94.     }
  95.     else {        /* Already a handler for this; just put in chain */
  96.         ap->ichain = ivec[vec].ichain ;    /* Put at head */
  97.         ivec[vec].ichain = &asy[dev] ;
  98.     }
  99.     
  100.     /* Update vector reference count */
  101.     ivec[vec].refcnt++ ;
  102.  
  103.     /* Save original control bits */
  104.     ap->save.lcr = inportb(base+LCR);
  105.     ap->save.ier = inportb(base+IER);
  106.     ap->save.mcr = inportb(base+MCR);
  107.  
  108.     /* save speed bytes */
  109.     setbit(base+LCR,LCR_DLAB);
  110.     ap->save.divl = inportb(base+DLL);
  111.     ap->save.divh = inportb(base+DLM);
  112.     clrbit(base+LCR,LCR_DLAB);
  113.  
  114.     /* Set line control register: 8 bits, no parity */
  115.     outportb(base+LCR,(char)LCR_8BITS);
  116.  
  117.     /* Turn on receive interrupt enable in 8250, leave transmit
  118.      * and modem status interrupts turned off for now
  119.      */
  120.     outportb(base+IER,(char)IER_DAV);
  121.  
  122.     /* Set modem control register: assert DTR, RTS, turn on 8250
  123.      * master interrupt enable (connected to OUT2)
  124.      */
  125.     outportb(base+MCR,(char)(MCR_DTR|MCR_RTS|MCR_OUT2));
  126.  
  127.     /* Enable interrupt */
  128.     maskon(ap->vec);
  129.     restore(i_state);
  130. #endif /* PC9801 */
  131. }
  132. int
  133. asy_stop(iface)
  134. struct interface *iface;
  135. {
  136.     register unsigned base;
  137.     register struct asy *ap;
  138.     unsigned vec ;
  139.     char i_state;
  140.  
  141.     ap = &asy[iface->dev];
  142.     base = ap->addr;
  143.  
  144. #ifndef PC9801
  145.     /* Purge the receive data buffer */
  146.     (void)inportb(base+RBR);
  147.  
  148.     /* See if this is the last asy using this interrupt, */
  149.     /* and restore the vector and interrupt mask if it is */
  150.     vec = ap->vec ;
  151.     if (--ivec[vec].refcnt == 0) {
  152.         i_state = disable();
  153.         setirq(ap->vec,ivec[vec].oldvec);
  154.         if(ivec[vec].oldmask)
  155.             maskon(ap->vec);
  156.         else
  157.             maskoff(ap->vec);
  158.         restore(i_state);
  159.     }
  160.  
  161.     /* Restore original interrupt vector and 8259 mask state */
  162.     /* Restore speed regs */
  163.     setbit(base+LCR,LCR_DLAB);
  164.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  165.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  166.     clrbit(base+LCR,LCR_DLAB);
  167.  
  168.     /* Restore control regs */
  169.     outportb(base+LCR,ap->save.lcr);
  170.     outportb(base+IER,ap->save.ier);
  171.     outportb(base+MCR,ap->save.mcr);
  172. #endif /* PC9801 */
  173. }
  174. /* Asynchronous line I/O control */
  175. asy_ioctl(interface,argc,argv)
  176. struct interface *interface;
  177. int argc;
  178. char *argv[];
  179. {
  180.     if(argc < 1){
  181.         printf("%d\r\n",asy[interface->dev].speed);
  182.         return 0;
  183.     }
  184.     return asy_speed(interface->dev,atoi(argv[0]));
  185. }
  186. /* Set asynch line speed */
  187. int
  188. asy_speed(dev,speed)
  189. int16 dev;
  190. int speed;
  191. {
  192. #ifdef PC9801
  193.   register int s_code, speed1;
  194.  
  195.   if (speed ==0 || speed >= 10000 || dev >= nasy)
  196.     return -1;
  197.  
  198.   speed1 = 75;
  199.   for (s_code = 0; speed >= speed1; s_code++) speed1 *= 2;
  200.   speed1 /= 2;
  201.   asy[dev].speed = speed1;
  202.   set_speed(s_code);
  203. #else
  204.     register unsigned base;
  205.     register int divisor;
  206.     char i_state;
  207.  
  208.     if(speed == 0 || dev >= nasy)
  209.         return -1;
  210.     
  211.     base = asy[dev].addr;
  212.     asy[dev].speed = speed;
  213.  
  214.     divisor = BAUDCLK / (long)speed;
  215.  
  216.     i_state = disable();
  217.  
  218.     /* Purge the receive data buffer */
  219.     (void)inportb(base+RBR);
  220.  
  221.     /* Turn on divisor latch access bit */
  222.     setbit(base+LCR,LCR_DLAB);
  223.  
  224.     /* Load the two bytes of the register */
  225.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  226.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  227.  
  228.     /* Turn off divisor latch access bit */
  229.     clrbit(base+LCR,LCR_DLAB);
  230.  
  231.     restore(i_state);
  232.     return 0;
  233. #endif /* PC9801 */
  234. }
  235.  
  236. /* Send a buffer to serial transmitter */
  237. asy_output(dev,buf,cnt)
  238. unsigned dev;
  239. char *buf;
  240. unsigned short cnt;
  241. {
  242. #ifdef PC9801
  243.   int b_cnt, b_buf;
  244.  
  245.   if (dev >= nasy) return;
  246.   for (b_cnt = 0; b_cnt < cnt; b_cnt++) {
  247.     b_buf = buf[b_cnt];
  248.     aput(b_buf);
  249.   }
  250. #else
  251.     register struct dma *dp;
  252.     unsigned base;
  253.     char i_state;
  254.  
  255.     if(dev >= nasy)
  256.         return;
  257.     base = asy[dev].addr;
  258.     dp = &asy[dev].dma;
  259.     i_state = disable();
  260.     if(dp->flags){
  261.         restore(i_state);
  262.         return;    /* Already busy */
  263.     }
  264.     dp->data = buf;
  265.     dp->cnt = cnt;
  266.     dp->flags = 1;
  267.     /* Enable transmitter buffer empty interrupt and simulate
  268.      * an interrupt; this will get things rolling.
  269.      */
  270.     setbit(base+IER,IER_TxE);
  271.     asytxint(dev);
  272.     restore(i_state);
  273. #endif /* PC9801 */
  274. }
  275. /* Receive characters from asynch line
  276.  * Returns count of characters read
  277.  */
  278. int16
  279. asy_recv(dev,buf,cnt)
  280. int16 dev;
  281. char *buf;
  282. unsigned cnt;
  283. {
  284.     unsigned tot,n;
  285. #ifdef PC9801
  286.     int ch;
  287.     
  288.     for (tot = 0; tot < cnt; tot++) {
  289.       if (auxstat()) ch = aget();
  290.       else break;
  291.       buf[tot] = ch;
  292.     }
  293.     return tot;
  294. }
  295.  
  296. #else
  297.     int kbread();
  298.     char i_state;
  299.     struct fifo *fp;
  300.  
  301.     fp = &asy[dev].fifo;
  302.     tot = 0;
  303.     /* Read from serial I/O input buffer */
  304.     i_state = disable();
  305.     for(;;){
  306.         n = min(cnt,fp->cnt);
  307.         if(n == 0)
  308.             break;
  309.         n = min(n,&fp->buf[fp->bufsize] - fp->rp);
  310.         memcpy(buf,fp->rp,n);
  311.         fp->rp += n;
  312.         if(fp->rp >= &fp->buf[fp->bufsize])
  313.             fp->rp = fp->buf;
  314.         fp->cnt -= n;
  315.         buf += n;
  316.         tot += n;
  317.         cnt -= n;
  318.     }
  319.     restore(i_state);
  320.     return tot;
  321.  
  322. }
  323. /* Interrupt handler for 8250 asynch chip */
  324. void
  325. asyint(handler)
  326. unsigned handler;
  327. {
  328.     register unsigned base;
  329.     register char iir;
  330.     register unsigned dev ;
  331.     struct asy *ap ;
  332.     int someint ;
  333.  
  334.     /* The following bears some explaining.  Because the PC and AT
  335.      * (but not the PS/2) uses edge triggered interrupts, we need
  336.      * to assure that the shared interrupt line makes a low-going
  337.      * transition before we issue an EOI.  If we don't, one of the
  338.      * UARTs could raise its interrupt line again after we serviced
  339.      * it, but before we cleared all the other UARTs' interrupts,
  340.      * and this would be missed by the interrupt controller in
  341.      * edge triggered mode.  This should still work fine on a
  342.      * PS/2.
  343.      * Many thanks to Dan Dodge of Quantum Software, Ltd., for
  344.      * suggesting this trick.  dmf
  345.      */
  346.     
  347.     do {                    
  348.  
  349.         someint = 0 ;    /* No interrupt detected yet on this pass */
  350.         
  351.         ap = ivec[h2ivec[handler]].ichain ;    /* Start at head of chain */
  352.  
  353.         while (ap != NULLASY) {
  354.             dev = ap - asy ;
  355.             base = asy[dev].addr;
  356.             while(((iir = inportb(base+IIR)) & IIR_IP) == 0) {
  357.                 someint = 1 ;    /* Detected an interrupt */
  358.                 switch(iir & IIR_ID){
  359.                 case IIR_RDA:    /* Receiver interrupt */
  360.                     asyrxint(dev);
  361.                     break;
  362.                 case IIR_THRE:    /* Transmit interrupt */
  363.                     asytxint(dev);
  364.                     break;
  365.                 }
  366.             }
  367.             ap = ap->ichain ;    /* step to next in chain */
  368.         }
  369.         
  370.     } while (someint != 0) ;
  371. }
  372. /* Process 8250 receiver interrupts */
  373. static
  374. asyrxint(dev)
  375. unsigned dev;
  376. {
  377.     unsigned base;
  378.     register struct fifo *fp;
  379.     char c;
  380.  
  381.     base = asy[dev].addr;
  382.     fp = &asy[dev].fifo;
  383.     while(inportb(base+LSR) & LSR_DR){
  384.         c = inportb(base+RBR);
  385.         /* Process incoming data;
  386.          * If buffer is full, we have no choice but
  387.          * to drop the character
  388.          */
  389.         if(fp->cnt != fp->bufsize){
  390.             *fp->wp++ = c;
  391.             if(fp->wp == &fp->buf[fp->bufsize])
  392.                 /* Wrap around */
  393.                 fp->wp = fp->buf;
  394.             fp->cnt++;
  395.         }
  396.     }
  397. }
  398. /* Handle 8250 transmitter interrupts */
  399. static
  400. asytxint(dev)
  401. unsigned dev;
  402. {
  403.     register struct dma *dp;
  404.     register unsigned base;
  405.     unsigned urg;    /* urgent SLFP data, or == 256 */
  406.  
  407.     base = asy[dev].addr;
  408.     dp = &asy[dev].dma;
  409.     if(!dp->flags){
  410.         /* "Shouldn't happen", but disable transmit
  411.          * interrupts anyway
  412.          */
  413.         clrbit(base+IER,IER_TxE);
  414.         return;    /* Nothing to send */
  415.     }
  416.     while(inportb(base+LSR) & LSR_THRE){
  417.         /* Send any pending urgent data */
  418.         if (asy[dev].urgent != NULLCHAR)
  419.             if ((urg = (*asy[dev].urgent)(dev)) < 256) {
  420.                 outportb(base+THR,urg);
  421.                 continue;
  422.             }
  423.         dp->last_octet = *dp->data;
  424.         outportb(base+THR,*dp->data++);
  425.         if(--dp->cnt == 0){
  426.             dp->flags = 0;
  427.             /* Disable transmit interrupts */
  428.             clrbit(base+IER,IER_TxE);
  429.             /* Call completion interrupt here */
  430.             break;
  431.         }
  432.     }
  433. }
  434.  
  435. /* Set bit(s) in I/O port */
  436.  
  437. setbit(port,bits)
  438. unsigned port;
  439. char bits;
  440. {
  441.     outportb(port,(char)inportb(port)|bits);
  442. }
  443. /* Clear bit(s) in I/O port */
  444. clrbit(port,bits)
  445. unsigned port;
  446. char bits;
  447. {
  448.     outportb(port,(char)(inportb(port) & ~bits));
  449. }
  450. #endif /* PC9801 */
  451.  
  452. int
  453. stxrdy(dev)
  454. int16 dev;
  455. {
  456.     return(!asy[dev].dma.flags);
  457. }
  458.  
  459. #ifdef PC9801
  460. auxopen()
  461. {
  462.   char *device;
  463.   device = "AUX";
  464.   work = jkintdos(0x3d02,0,device);
  465.   return (work);
  466. }
  467.  
  468. auxstat() 
  469. {
  470.   work = jkintdos(0x4406,f_handle,0) & mask;
  471.   return (work);
  472. }
  473.  
  474. aget()
  475. {
  476.   work = jkintdos(0x0300,0,0) & mask;
  477.   return (work);
  478. }
  479.  
  480. aput(ch)
  481.      int ch;
  482. {
  483.   jkintdos(0x0400,0,ch);
  484. }
  485. #endif /* PC9801 */
  486. #endif /* !defined(PLUS) */
  487.